#include "fs.h"

#include "print.h"
#include "ide.h"
#include "global.h"
#include "inode.h"
#include "super_block.h"
#include "dir.h"
#include "memory.h"
#include "debug.h"
#include "stdio_kernel.h"
#include "string.h"
#include "stdint.h"
#include "file.h"
#include "console.h"
#include "keyboard.h"
#include "ioqueue.h"

extern struct dir root_dir;
struct file file_table[MAX_FILE_OPEN]; 
struct partition* cur_part;

/* 格式化分区, 初始化分区信息, 创建文件系统 */
static void partition_format(struct disk* hd, struct partition* part)
{
    uint32_t boot_sector_sect = 1;
    uint32_t super_block_sect = 1;
    // inode位图占用扇区数=1
    uint32_t inode_bitmap_sects = DIV_ROUND_UP(MAX_FILES_PER_PART, BITS_PER_SECTOR);
    // inode_table占用扇区数
    uint32_t inode_table_sects = DIV_ROUND_UP(((sizeof(struct inode)*MAX_FILES_PER_PART)), 
                                 SECTOR_SIZE);
    uint32_t used_sects = boot_sector_sect + super_block_sect + 
                          inode_bitmap_sects + inode_table_sects;
    uint32_t free_sects = part->sec_cnt - used_sects;

// 只迭代两次, 但够用.  
    uint32_t block_bitmap_sects;
    block_bitmap_sects = DIV_ROUND_UP(free_sects, BITS_PER_SECTOR);
    // 被映射的block,扇区数
    uint32_t block_bitmap_bit_len = free_sects - block_bitmap_sects; 
    // bitmap扇区数
    block_bitmap_sects = DIV_ROUND_UP(block_bitmap_bit_len, BITS_PER_SECTOR);

    struct super_block sb;
    sb.magic = 0x19590318;
    sb.sec_cnt = part->sec_cnt;
    sb.inode_cnt = MAX_FILES_PER_PART;
    sb.part_lba_base = part->start_lba;

    // 块位图开始lba
    sb.block_bitmap_lba = sb.part_lba_base + 2;
    sb.block_bitmap_sects = block_bitmap_sects;
    
    // inode位图开始lba
    sb.inode_bitmap_lba = sb.block_bitmap_lba + sb.block_bitmap_sects;
    sb.inode_bitmap_sects = inode_bitmap_sects;

    // inode表开始lba
    sb.inode_table_lba = sb.inode_bitmap_lba + sb.inode_bitmap_sects;
    sb.inode_table_sects = inode_table_sects;

    // 数据块开始lba
    sb.data_start_lba = sb.inode_table_lba + sb.inode_table_sects;

    sb.root_inode_no = 0; // root目录inode
    sb.dir_entry_size = sizeof(struct dir_entry);

    printk("%s info:\n", part->name);
    printk("magic:0x%x\n", sb.magic);
    printk("part_lba_base:0x%x\n", sb.part_lba_base);
    printk("all_sectors:0x%x\ninode_cnt:0x%x\n", sb.sec_cnt, sb.inode_cnt);
    printk("block_bitmap_lba:0x%x\nblock_bitmap_sectors:0x%x\n", sb.block_bitmap_lba, sb.block_bitmap_sects);
    printk("inode_bitmap_lba:0x%x\ninode_bitmap_sectors:0x%x\n", sb.inode_bitmap_lba, sb.inode_bitmap_sects);
    printk("inode_table_lba:0x%x\ninode_table_sectors:0x%x\n", sb.inode_table_lba, sb.inode_table_sects);
    printk("data_start_base:0x%x\n", sb.data_start_lba);

    /* 1. 将超级块写入本分区的1扇区, +1因前为操作系统引导块, 占1扇区 */
    ide_write(hd, part->start_lba+1, &sb, 1);
    printk("super_block_lba:0x%x\n", part->start_lba+1);

    uint32_t buf_size = (sb.block_bitmap_sects >= sb.inode_bitmap_sects ? 
                         sb.block_bitmap_sects : sb.inode_bitmap_sects);
    buf_size = (buf_size >= sb.inode_table_sects ? 
                         buf_size : sb.inode_table_sects)*SECTOR_SIZE;
    uint8_t* buf = (uint8_t*)sys_malloc(buf_size);

    /* 2. 将block bitmap初始化写入sb.block_bitmap_lba */
    buf[0] |= 0x01; // 第0块为根目录 
    // block_bitmap的字节数
    uint32_t block_bitmap_last_byte = block_bitmap_bit_len / 8;
    // bitmap最后一字节可用bit 
    uint8_t block_bitmap_last_bit = block_bitmap_bit_len % 8;
    // 
    uint32_t last_size = SECTOR_SIZE - (block_bitmap_last_byte % SECTOR_SIZE);
    memset(&buf[block_bitmap_last_byte], 0xff, last_size);
    uint8_t bit_idx=0;
    while(bit_idx <= block_bitmap_last_bit) {
        buf[block_bitmap_last_byte] &=~(1 << bit_idx++);
    }
    ide_write(hd, sb.block_bitmap_lba, buf, sb.block_bitmap_sects);

    /* 3. 将inode bitmapt初始化写入sb.inode_bitmap_lba */
        memset(buf, 0, buf_size);
        buf[0] |= 0x1;    // 第0个inode分给根目录 
        ide_write(hd, sb.inode_bitmap_lba, buf, sb.inode_bitmap_sects);

    /* 4. 将inode table初始化写入sb.inode_table_lba */
        memset(buf, 0, buf_size);
        // 根目录inode
        struct inode* i = (struct inode*)buf;
        i->i_size = sb.dir_entry_size * 2; // .和..
        i->i_no = 0;
        i->i_sectors[0] = sb.data_start_lba;
        ide_write(hd, sb.inode_table_lba, buf, sb.inode_table_sects);

    /* 5. 将根目录写入sb.data_start_lba */
        memset(buf, 0, buf_size);
        struct dir_entry* p_de = (struct dir_entry*)buf;

        memcpy(p_de->filename, ".", 1);
        p_de->i_no = 0;
        p_de->f_type = FT_DIRECTORY;
        p_de++;
        
        memcpy(p_de->filename, "..", 2);
        p_de->i_no = 0;
        p_de->f_type = FT_DIRECTORY;

        ide_write(hd, sb.data_start_lba, buf, 1);
        printk("root_dir_lba:0x%x\n", sb.data_start_lba);
        printk("%s format done\n", part->name);
        sys_free(buf);
}

/* 挂载arg分区 */
static bool mount_partition(struct list_elem* pelem, int arg)
{
    char* part_name = (char*)arg;
    struct partition* part = elem2entry(struct partition, part_tag, pelem);
    if(!strcmp(part->name, part_name)) {
        /* 读取part_name分区的元信息 */
        cur_part = part;
        struct disk* hd = cur_part->my_disk;
        struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);
        // 1. 将硬盘中的super_block加载到分区part中
        cur_part->sb = (struct super_block*)sys_malloc(sizeof(struct super_block));
        if(cur_part->sb == NULL) {
            PANIC("alloc memory failed!");
        }
        memset(sb_buf, 0, SECTOR_SIZE);

        ide_read(hd, cur_part->start_lba+1, sb_buf, 1);
        memcpy(cur_part->sb, sb_buf, sizeof(struct super_block));

        // 2. 将硬盘中的inode_bitmap 和 block_bitmap加载到分区part中
        cur_part->block_bitmap.bits = 
            (uint8_t*)sys_malloc(sb_buf->block_bitmap_sects*SECTOR_SIZE);
        if(cur_part->block_bitmap.bits == NULL) {
            PANIC("alloc memory failed!");
        }
        cur_part->block_bitmap.btmp_bytes_len = 
            sb_buf->block_bitmap_sects * SECTOR_SIZE;
        ide_read(hd, sb_buf->block_bitmap_lba, 
                     cur_part->block_bitmap.bits, sb_buf->block_bitmap_sects);
        
        cur_part->inode_bitmap.bits = 
            (uint8_t*)sys_malloc(sb_buf->inode_bitmap_sects*SECTOR_SIZE); 
        if(cur_part->inode_bitmap.bits == NULL) {
            PANIC("alloc memory failed!");
        }
        cur_part->inode_bitmap.btmp_bytes_len = 
            sb_buf->inode_bitmap_sects * SECTOR_SIZE;
        ide_read(hd, sb_buf->inode_bitmap_lba, 
            cur_part->inode_bitmap.bits, sb_buf->inode_bitmap_sects);

        list_init(&cur_part->open_inodes);
        printk("mount %s done!\n", cur_part->name);

        return true;
    }

    return false;
}

void filesys_init()
{
    uint8_t channel_no = 0, dev_no, part_idx = 0;
    struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);

    if(sb_buf == NULL) {
        PANIC("alloc memory failed!");
    }
    printk("searching filesystem.....\n");

    while(channel_no < channel_cnt) {
        dev_no = 0;
        while(dev_no < 2) {
            if(dev_no == 0) {
                dev_no++;
                continue;
            }
            struct disk* hd = &channels[channel_no].device[dev_no];
            struct partition* part = hd->prim_parts;
            while(part_idx < 12) {
                if(part_idx == 4) {
                    part = hd->logic_parts;
                }
                if(part->sec_cnt != 0) {
                    memset(sb_buf, 0, SECTOR_SIZE);
                    ide_read(hd, part->start_lba+1, sb_buf, 1);

                    if(sb_buf->magic == 0x19590318) {
                        printk("%s has filesystem\n", part->name);
                    } else {
                        printk("formatting %s's partition %s .....\n", hd->name, part->name);
                        partition_format(part->my_disk, part);
                    }
                }
                part_idx++;
                part++;
            }
            dev_no++;
        }
        channel_no++;
    }
    sys_free(sb_buf);


    char default_part[8] = "sdb1";
    // 系统启动后, 默认加载sdb1分区
    list_traversal(&partition_list, mount_partition, (int)default_part);

    open_root_dir(cur_part);
    uint32_t file_idx = 0;
    while(file_idx < MAX_FILE_OPEN) {
        file_table[file_idx++].file_inode = NULL;
    }
}

char* path_parse(char* pathname, char* name_store)
{
    if(pathname[0] == '/') {
        while(*(++pathname) == '/');
    }

    while(*pathname != '/' && *pathname != 0) {
        *name_store++ = *pathname++;
    }

    if(pathname[0] == 0) {
        return NULL;
    }

    return pathname;
}

int32_t path_depth_cnt(char* pathname) 
{
    ASSERT(pathname != NULL);
    char* p = pathname;
    char name[MAX_FILE_NAME_LEN];

    uint32_t depth = 0;
    p = path_parse(p, name);
    while(name[0]) {
        depth++;
        memset(name, 0, MAX_FILE_NAME_LEN);
        if(p) {
            p = path_parse(p, name);
        }
    }
    return depth;
}

/* 搜索文件pathname, 若找到返回其inode, 否则返回-1*/
static int search_file(const char* pathname, struct path_search_record* search_record)
{
    // 根目录的'.'和'..', 都是'/'
    if(!strcmp(pathname, "/") || !strcmp(pathname, "/.") 
       || !strcmp(pathname, "/.."))
    {
        search_record->parent_dir = &root_dir;
        search_record->file_type = FT_DIRECTORY;    
        search_record->searched_path[0] = 0;
        return 0;
    } 

    uint32_t path_len = strlen(pathname);
    ASSERT(pathname[0] == '/' && path_len > 1 && path_len < MAX_PATH_LEN);
    char* sub_path = (char*)pathname;

    struct dir* parent_dir = &root_dir; // 父目录从根目录开始
    struct dir_entry dir_e;
    char name[MAX_FILE_NAME_LEN] = {0};

    search_record->parent_dir = parent_dir;
    search_record->file_type = FT_UNKNOWN;
    uint32_t parent_inode_no = 0;

    sub_path = path_parse(sub_path, name); // 去除第一个目录
    while(name[0]) {
        ASSERT(strlen(search_record->searched_path) < 512);
        strcat(search_record->searched_path, "/");
        strcat(search_record->searched_path, name);

        if(search_dir_entry(cur_part, parent_dir, name, &dir_e)) {
            memset(name, 0, MAX_FILE_NAME_LEN);
            if(sub_path) {
                sub_path = path_parse(sub_path, name);
            }
            if(FT_DIRECTORY == dir_e.f_type) {
                parent_inode_no = parent_dir->inode->i_no;
                dir_close(parent_dir);
                parent_dir = dir_open(cur_part, dir_e.i_no);
                search_record->parent_dir = parent_dir;
                continue;
            } else if (FT_REGULAR == dir_e.f_type) {
                search_record->file_type = FT_REGULAR;
                return dir_e.i_no;
            }
        } else {
            return -1;
        }
    }

    dir_close(search_record->parent_dir);
    search_record->parent_dir = dir_open(cur_part, parent_inode_no);
    search_record->file_type = FT_DIRECTORY;
    return dir_e.i_no;
}

// 先实现创建文件部分
int32_t sys_open(const char* pathname, enum oflags flag)
{
    // 判断pathname是否为普通文件, sys_open只能打开普通文件
    if(pathname[strlen(pathname)-1] == '/') {
        printk("cant open a dircectory %s\n", pathname);
        return -1;
    }

    ASSERT(flag <= 7);// O_CREAT|O_RDONLY|O_WRONLY|O_RDWR <=7
    struct path_search_record search_record;
    memset(&search_record, 0, sizeof(struct path_search_record));
    uint32_t pathname_depth = path_depth_cnt((char*)pathname);
    // 检查pathname是否已存在. 
    int inode_no = search_file(pathname, &search_record);
    
    bool found = inode_no != -1 ? true : false;
    // 不存在:最后目录中不存在, 结合flag进行下一步操作;不是最后目录中不存在, 失败
    // 存在: 是否是普通文件, 是, 打开文件; 不是, 失败 
    if(search_record.file_type == FT_DIRECTORY) {
        printk("cant open a direcotry with open()\n");
        dir_close(search_record.parent_dir);
        return -1;
    }

    uint32_t path_search_depath = path_depth_cnt(search_record.searched_path);

    if(pathname_depth != path_search_depath) {
        printk("cannot access %s: Nnt a director, subpath %s ist exist\n",
                pathname, search_record.searched_path);
        dir_close(search_record.parent_dir);
        return -1;
    }

    if(!found && !(flag&O_CREAT)) {
        printk("not O_creat\n");
        dir_close(search_record.parent_dir);
        return -1;
    } else if (found && flag & O_CREAT) {
        printk("%s has already exist\n", pathname);
        dir_close(search_record.parent_dir);
        return -1;
    }
    int32_t fd = -1;
    switch(flag&O_CREAT) {
        case O_CREAT:
            printk("creating file\n");
            fd = file_create(search_record.parent_dir, (strrchr(pathname,'/')+1), flag);
            dir_close(search_record.parent_dir);
            break;
        default: // 打开已存在文件o_rdonly, o_wronly, o_rdwr
            fd = file_open(inode_no, flag);
    }
    return fd;
}

// 将文件描述符转化为文件表下标
static uint32_t fd_local2filetable(uint32_t local_fd) 
{
    struct task_struct* cur = running_thread();
    int32_t filetable_idx = cur->fd_table[local_fd];
    ASSERT(filetable_idx >= 0 && filetable_idx < MAX_FILE_OPEN);
    return (uint32_t)filetable_idx;
}

// 关闭文件描述符fd文件
int32_t sys_close(int32_t fd) 
{
    int32_t ret = -1;
    if(fd > 2) {
        uint32_t filetable_idx = fd_local2filetable(fd);
        ret = file_close(&file_table[filetable_idx]);
        running_thread()->fd_table[fd] = -1;
    }
    return ret;
}

int32_t sys_write(int32_t fd, const void* buf, uint32_t count)
{
    if(fd < 0) {
        printk("sys_write: fd error");
        return -1;
    }

    if(fd == stdout_no) {
        char tmp_buf[1024] = {0};
        memcpy(tmp_buf, buf, count);
        console_put_str(tmp_buf);
        return count;
    }

    uint32_t file_idx = fd_local2filetable(fd);
    struct file* wr_file = &file_table[file_idx];
    if(wr_file->file_flags & O_WRONLY || wr_file->file_flags&O_RDWR) {
        uint32_t written_bytes = file_write(wr_file, buf, count);
        return written_bytes;
    } else {
        console_put_str("sys_write: not allowed to write file without flag o_rdwr or o_wronly\n");
        return -1;
    }
}

int32_t sys_read(int32_t fd, void* buf, uint32_t count) 
{
    ASSERT(buf != NULL);
    int32_t ret = -1;
    if(fd < 0 || fd == stdout_no || fd == stderr_no) {
        printk("sys_read: fd error\n");
    } else if (fd == stdin_no) {
        char* buffer = buf;
        uint32_t bytes_read = 0;
        while (bytes_read < count) {
            *buffer = ioq_getchar(&kbd_buf);
            bytes_read++;
            buffer++;
        }
        ret = (bytes_read == 0 ? -1 : (int32_t)bytes_read);
    } else {
        uint32_t file_idx = fd_local2filetable(fd);
        ret = file_read(&file_table[file_idx], buf, count);
    }
    return ret;
}

int32_t sys_lseek(int32_t fd, int32_t offset, uint8_t lflag)
{
    if (fd<0) {
        printk("sys_lseek: fd error\n");
        return -1;
    }
    ASSERT(lflag>0 && lflag<4);
    uint32_t file_idx = fd_local2filetable(fd);
    struct file *pf = &file_table[file_idx];
    int32_t new_pos = 0;
    int32_t file_size = (int32_t)pf->file_inode->i_size;
    switch(lflag) {
        case SEEK_SET:
            new_pos = offset;
            break;
        case SEEK_CUR:
            new_pos = (int32_t)pf->file_pos + offset;
            break;
        case SEEK_END:
            new_pos = file_size + offset;
    }

    if(new_pos<0 || new_pos>(file_size-1)) {
        return -1;
    }
    pf->file_pos = new_pos;
    return pf->file_pos;
}

int32_t sys_unlink(const char *pathname) 
{
    ASSERT(strlen(pathname) < MAX_PATH_LEN);
    // 检查待删除文件是否存在
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));

    int inode_no = search_file(pathname, &searched_record);
    
    ASSERT(inode_no != 0);
    if(inode_no == -1) {
        printk("file %s not found\n", pathname);
        dir_close(searched_record.parent_dir);
        return -1;
    }

    if(searched_record.file_type == FT_DIRECTORY) {
        printk("this is not file, is directory, cant delete directory");
        dir_close(searched_record.parent_dir);
        return -1;
    }

    // 检查删除的文件是否打开, 若打开不能删除
    uint32_t file_idx = 0;
    while(file_idx < MAX_FILE_OPEN) {
        if (file_table[file_idx].file_inode != NULL 
                && (uint32_t)inode_no == file_table[file_idx].file_inode->i_no) 
        {
            break;
        }
        file_idx++;
    }
    if (file_idx < MAX_FILE_OPEN) {
        dir_close(searched_record.parent_dir);
        printk("file %s is in use, not allow to delete\n", pathname);
        return -1;
    }
    ASSERT(file_idx == MAX_FILE_OPEN);

    void *io_buf = sys_malloc(SECTOR_SIZE + SECTOR_SIZE);
    if(io_buf == NULL) {
        dir_close(searched_record.parent_dir);
        printk("sys_unlink: malloc for io_buf failed\n");
        return -1;
    }

    struct dir *parent_dir = searched_record.parent_dir;
    delete_dir_entry(cur_part, parent_dir, inode_no, io_buf);
    inode_release(cur_part, inode_no);
    sys_free(io_buf);
    dir_close(searched_record.parent_dir);
    return 0;
}
/*
2. 为新目录创建inode
3. 为新目录分配1个块存储该目录的目录项
*/
int32_t sys_mkdir(const char* pathname)
{
    uint8_t rollback_step = 0;
    void *io_buf = sys_malloc(SECTOR_SIZE*2);
    if(io_buf==NULL) {
        printk("sys_mkdir: io_buf failed\n");
        return -1;
    }
// 1. 确认待创建的新目录不存在. 并且中间目录不缺失
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = -1;
    inode_no = search_file(pathname, &searched_record);
    if(inode_no != -1) {
        printk("sys_mkdir: file or directory %s exist\n", pathname);
        rollback_step = 1;
        goto rollback;
    } else {
        uint32_t pathname_depth = path_depth_cnt((char*)pathname);
        uint32_t path_searched_depth = path_depth_cnt(searched_record.searched_path);
        if(pathname_depth != path_searched_depth) {
            printk("sys_mkdir: cannot access %s: not a directory, subpath %s ist exist\n", 
                   pathname, searched_record.searched_path);
            rollback_step = 1;
            goto rollback;
        }
    }

    struct dir *parent_dir = searched_record.parent_dir;
    char *dirname = strrchr(searched_record.searched_path, '/') + 1;
    inode_no = inode_bitmap_alloc(cur_part);
    if(inode_no == -1) {
        printk("sys_mkdir: allocate inode failed\n");
        rollback_step = 1;
        goto rollback;
    }
    struct inode new_dir_inode;
    inode_init(inode_no, &new_dir_inode);
    uint32_t block_bitmap_idx = 0;
    int32_t block_lba = -1;
    block_lba = block_bitmap_alloc(cur_part);
    if(block_lba == -1) {
        printk("sys_mkdir: block_bitmap_alloc for create directory failed\n");
        rollback_step = 2;
        goto rollback;
    }
    new_dir_inode.i_sectors[0] = block_lba;
    block_bitmap_idx = block_lba - cur_part->sb->data_start_lba;
    ASSERT(block_bitmap_idx != 0);
    bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);

// 4. 在新目录中添加.和..目录项
    memset(io_buf, 0, SECTOR_SIZE*2);
    struct dir_entry *p_de = (struct dir_entry*)io_buf;

    memcpy(p_de->filename, ".", 1);
    p_de->i_no = inode_no;
    p_de->f_type = FT_DIRECTORY;
    p_de++;

    memcpy(p_de->filename, "..", 2);
    p_de->i_no = parent_dir->inode->i_no;
    p_de->f_type = FT_DIRECTORY;
    ide_write(cur_part->my_disk, new_dir_inode.i_sectors[0], io_buf, 1);
    new_dir_inode.i_size = 2*cur_part->sb->dir_entry_size;

// 5. 为新目录的父目录添加该目录的目录项
    struct dir_entry new_dir_entry;
    memset(&new_dir_entry, 0, sizeof(struct dir_entry));
    create_dir_entry(dirname, inode_no, FT_DIRECTORY, &new_dir_entry);
    memset(io_buf, 0, SECTOR_SIZE*2);
    if(!sync_dir_entry(parent_dir, &new_dir_entry, io_buf)) {
        printk("sys_mkdir: sync_dir_entry to disk failed\n");
        rollback_step = 2;
        goto rollback;
    } 

// 6. 同步
    memset(io_buf, 0, SECTOR_SIZE*2);
    inode_sync(cur_part, parent_dir->inode, io_buf);

    memset(io_buf, 0, SECTOR_SIZE*2);
    inode_sync(cur_part, &new_dir_inode, io_buf);

    bitmap_sync(cur_part, inode_no, INODE_BITMAP);
    sys_free(io_buf);

    dir_close(searched_record.parent_dir);
    return 0;

    rollback:
        switch (rollback_step) {
            case 2:
                bitmap_set(&cur_part->inode_bitmap, inode_no, 0);
            case 1:
                dir_close(searched_record.parent_dir);
                break;

        }
        sys_free(io_buf);
        return -1;
}

struct dir* sys_opendir(const char *name)
{
    ASSERT(strlen(name) < MAX_PATH_LEN);
    if(name[0] == '/' && (name[1] == 0 || name[0] == '.')) {
        return &root_dir;
    }

    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(name, &searched_record);
    struct dir *ret = NULL;
    if(inode_no == -1) {
        printk("in %s, sub path %s not exist\n", name, searched_record.searched_path);
    } else {
        if (searched_record.file_type == FT_REGULAR) {
            printk("%s is regular file\n", name);
        } else if (searched_record.file_type == FT_DIRECTORY) {
            ret = dir_open(cur_part, inode_no);
        }
    }
    dir_close(searched_record.parent_dir);
    return ret;
}

int32_t sys_closedir(struct dir *dir) 
{
    int32_t ret = -1;
    if (dir != NULL) {
        dir_close(dir);
        ret = 0;
    }
    return ret;
}

struct dir_entry *sys_readdir(struct dir *dir) 
{
    ASSERT(dir != NULL);
    return dir_read(dir);
}

void sys_rewinddir(struct dir *dir)
{
    dir->dir_pos = 0;
}

int32_t sys_rmdir(const char *pathname)
{
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(pathname, &searched_record);
    ASSERT(inode_no != 0);

    int retval = -1;
    if (inode_no == -1) {
        printk("in %s, sub path %s not exist\n", pathname, searched_record.searched_path);
    } else {
        if (searched_record.file_type == FT_REGULAR) {
            printk("%s is regular file\n", pathname);
        } else {
            struct dir *dir  = dir_open(cur_part, inode_no);
            if (!dir_is_empty(dir)) {
                printk("dir %s id not empty, it is not allowed to delete a nonempty directory\n", pathname);
            } else {
                if (!dir_remove(searched_record.parent_dir, dir)) {
                    return 0;
                }
            }
            dir_close(dir);
        }
    }
    dir_close(searched_record.parent_dir);
    return retval;
}

/* 获得父目录的inode no*/
static uint32_t get_parent_dir_inode_no(uint32_t child_inode_no, void *io_buf)
{
    // 把child dir的第一个数据块读入内存, 目录项".."为父目录
    struct inode *child_dir_inode = inode_open(cur_part, child_inode_no);
    uint32_t block_lba = child_dir_inode->i_sectors[0];
    ASSERT(block_lba >= cur_part->sb->data_start_lba);
    inode_close(child_dir_inode);
    ide_read(cur_part->my_disk, block_lba, io_buf, 1);
    struct dir_entry *dir_e = (struct dir_entry*)io_buf;
    // dir_e[0]为".", dir_e[1]为".."
    ASSERT(dir_e[1].i_no < 4096 && dir_e[1].f_type == FT_DIRECTORY);
    return dir_e[1].i_no;
}

/* 在p_inode_no的目录中, 查找c_inode_no子目录. 找到后把名字存入path*/
static int get_child_dir_name(uint32_t p_inode_no, uint32_t c_inode_no, char *path, void *io_buf)
{
    struct inode *parent_dir_inode = inode_open(cur_part, p_inode_no);
    uint8_t block_idx = 0;
    uint32_t all_blocks[140] = {0}, block_cnt = 12;
    while (block_idx < 12) 
    {
        all_blocks[block_idx] = parent_dir_inode->i_sectors[block_idx];
        block_idx++;
    }

    if (parent_dir_inode->i_sectors[12]) 
    {
        ide_read(cur_part->my_disk, parent_dir_inode->i_sectors[12], all_blocks+12, 1);
        block_cnt = 140;
    }
    inode_close(parent_dir_inode);

    struct dir_entry *dir_e = (struct dir_entry*)io_buf;
    uint32_t dir_entry_size = cur_part->sb->dir_entry_size;
    uint32_t dir_entrys_per_sec = (SECTOR_SIZE/dir_entry_size);
    block_idx = 0;

    while (block_idx < block_cnt) 
    {
        if (all_blocks[block_idx]) 
        {
            ide_read(cur_part->my_disk, all_blocks[block_idx], io_buf, 1);
            uint8_t dir_e_idx = 0;
            while (dir_e_idx < dir_entrys_per_sec)
            {
                if ((dir_e + dir_e_idx)->i_no == c_inode_no)
                {
                    strcat(path, "/");
                    strcat(path, (dir_e + dir_e_idx)->filename);
                    return 0;
                }
                dir_e_idx++;
            }
        }
        block_idx++;
    }
    return -1;
}

// 把当前工作目录绝对路径写入buf
char* sys_getcwd(char *buf, uint32_t size)
{
    ASSERT(buf != NULL);
    void *io_buf = sys_malloc(SECTOR_SIZE);
    if (io_buf == NULL) {
        return NULL;
    }

    struct task_struct *cur_thread = running_thread();
    int32_t parent_inode_no = 0;
    int32_t child_inode_no = cur_thread->cwd_inode_no;
    ASSERT(child_inode_no >= 0 && child_inode_no < 4096);

    if (child_inode_no == 0)
    {
        buf[0] = '/';
        buf[1] = 0;
        sys_free(io_buf);
        return buf;
    }

    memset(buf, 0, size);
    char full_path_reverse[MAX_PATH_LEN] = {0};

    while ((child_inode_no))
    {
        parent_inode_no = get_parent_dir_inode_no(child_inode_no, io_buf);
        if (get_child_dir_name(parent_inode_no, child_inode_no,
                full_path_reverse, io_buf) == -1)
        {
            sys_free(io_buf);
            return NULL;
        }
        child_inode_no = parent_inode_no;
    }
    ASSERT(strlen(full_path_reverse) <= size);

    char *last_slash;
    while ((last_slash = strrchr(full_path_reverse, '/')))
    {
        uint16_t len = strlen(buf);
        strcpy(buf + len, last_slash);
        *last_slash = 0;
    }
    sys_free(io_buf);
    return buf;
}

int32_t sys_chdir(const char *path)
{
    int32_t ret = -1;
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(path, &searched_record);

    if (inode_no != -1)
    {
        if (searched_record.file_type == FT_DIRECTORY) 
        {
            running_thread()->cwd_inode_no = inode_no;
            ret = 0;
        } else {
            printk("sys_chdir: %s is regular file or other\n", path);
        }
    }
    dir_close(searched_record.parent_dir);
    return ret;
}

int32_t sys_stat(const char *path, struct stat *buf)
{
    if (!strcmp(path, "/") || !strcmp(path, "/.") || !strcmp(path, "/.."))
    {
        buf->st_filetype = FT_DIRECTORY;
        buf->st_ino = 0;
        buf->st_size = root_dir.inode->i_size;
        return 0;
    }

    int32_t ret = -1;
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));

    int inode_no = search_file(path, &searched_record);
    if (inode_no != -1)
    {
        struct inode *obj_inode = inode_open(cur_part, inode_no);
        buf->st_size = obj_inode->i_size;
        inode_close(obj_inode);
        buf->st_filetype = searched_record.file_type;
        buf->st_ino = inode_no;
        ret = 0;
    } else {
        printk("sys_stat: %s not found\n", path);
    }
    dir_close(searched_record.parent_dir);
    return ret;
}

void sys_putchar(char char_asci)
{
    console_put_char(char_asci);
}